package com.example.javagobang.api;

import com.example.javagobang.constant.Constants;
import com.example.javagobang.game.OnlineUser;
import com.example.javagobang.game.RoomManager;
import com.example.javagobang.mapper.UserInfoMapper;
import com.example.javagobang.model.GameReadyResponse;
import com.example.javagobang.model.GameResponse;
import com.example.javagobang.model.Room;
import com.example.javagobang.model.UserInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
public class GameAPI extends TextWebSocketHandler {
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RoomManager roomManager;
    @Autowired
    private OnlineUser onlineUser;
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        GameReadyResponse resp = new GameReadyResponse();
        //1.判断用户是否进行了登录的操作
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.user);

        if(userInfo == null){
            resp.setOk(false);
            resp.setReason("当前用户未登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }

        // 2. 判定当前用户是否已经进入房间. (拿着房间管理器进行查询)
        Room room = roomManager.getRoomByUserId(userInfo.getUserId());
        if (room == null) {
            // 如果为 null, 当前没有找到对应的房间. 该玩家还没有匹配到.
            resp.setOk(false);
            resp.setReason("用户尚未匹配到!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }
        //3.判断玩家是否多开
        if (onlineUser.getFromGameHall(userInfo.getUserId()) != null
                || onlineUser.getFromGameRoom(userInfo.getUserId()) != null) {
            // 如果一个账号, 一边是在游戏大厅, 一边是在游戏房间, 也视为多开~~
            resp.setOk(true);
            resp.setReason("禁止多开游戏页面");
            resp.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }

        //4设置上线
        onlineUser.enterGameRoom(userInfo.getUserId(),session);

        //5.进入房间
        synchronized (room) {
            if (room.getUser1() == null) {
                // 第一个玩家还尚未加入房间.
                // 就把当前连上 websocket 的玩家作为 user1, 加入到房间中.
                room.setUser1(userInfo);
                // 把先连入房间的玩家作为先手方.
                room.setWhiteUser(userInfo.getUserId());
                System.out.println("玩家 " + userInfo.getUsername() + " 已经准备就绪! 作为玩家1");
                return;
            }
            if (room.getUser2() == null) {
                // 如果进入到这个逻辑, 说明玩家1 已经加入房间, 现在要给当前玩家作为玩家2 了
                room.setUser2(userInfo);
                System.out.println("玩家 " + userInfo.getUsername() + " 已经准备就绪! 作为玩家2");

                // 当两个玩家都加入成功之后, 就要让服务器, 给这两个玩家都返回 websocket 的响应数据.
                // 通知这两个玩家说, 游戏双方都已经准备好了.
                // 通知玩家1
                noticeGameReady(room, room.getUser1(), room.getUser2());
                // 通知玩家2
                noticeGameReady(room, room.getUser2(), room.getUser1());
                return;
            }
        }

        //表示当前房间已经满了
        resp.setOk(false);
        resp.setReason("当前房间已满, 您不能加入房间");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
    }

    private void noticeGameReady(Room room, UserInfo thisUser, UserInfo thatUser) throws IOException {
        GameReadyResponse resp = new GameReadyResponse();
        resp.setMessage("gameReady");
        resp.setOk(true);
        resp.setReason("");
        resp.setRoomId(room.getRoomId());
        resp.setThisUserId(thisUser.getUserId());
        resp.setThatUserId(thatUser.getUserId());
        resp.setWhiteUser(room.getWhiteUser());

        String json = objectMapper.writeValueAsString(resp);
        WebSocketSession webSocketSession = onlineUser.getFromGameRoom(thisUser.getUserId());
        webSocketSession.sendMessage(new TextMessage(json));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.user);
        if(userInfo == null){
            System.out.println("用户未登录");
            return;
        }
        // 2. 根据玩家 id 获取到房间对象
        Room room = roomManager.getRoomByUserId(userInfo.getUserId());
        // 3. 通过 room 对象来处理这次具体的请求
        room.putChess(message.getPayload());

    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.user);

        if(userInfo == null){
            return;
        }

        WebSocketSession tempsession = onlineUser.getFromGameRoom(userInfo.getUserId());
        //防止下线操作误删之前登录的用户信息
        if(tempsession == session){
            onlineUser.exitGameRoom(userInfo.getUserId());
        }
        System.out.println("当前用户 " + userInfo.getUsername() + " 异常离开游戏房间!");
        noticThatUserWin(userInfo);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.user);

        if(userInfo == null){
            return;
        }

        WebSocketSession tempsession = onlineUser.getFromGameRoom(userInfo.getUserId());
        //防止下线操作误删之前登录的用户信息
        if(tempsession == session){
            onlineUser.exitGameRoom(userInfo.getUserId());
        }
        System.out.println("当前用户 " + userInfo.getUsername() + " 离开游戏房间!");
        noticThatUserWin(userInfo);
    }
    //判断下线问题
    private void noticThatUserWin(UserInfo userInfo) throws IOException {
        //根据玩家找到这里的房间
        Room room = roomManager.getRoomByUserId(userInfo.getUserId());

        if(room == null){
            //表示房间解散
            System.out.println("房间解散，无需判断胜负");
            return;
        }

        UserInfo thatUser = (userInfo == room.getUser1()) ? room.getUser2() : room.getUser1();


        WebSocketSession webSocketSession = onlineUser.getFromGameRoom(thatUser.getUserId());
        if(webSocketSession == null){
            System.out.println("玩家双方都掉线了，无需判断胜负");
            return;
        }
        GameResponse resp = new GameResponse();
        resp.setMessage("putChess");
        resp.setUserId(thatUser.getUserId());
        resp.setWinner(thatUser.getUserId());
        //防止默认打印棋子的位置
        resp.setCol(-1);

        webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));

         //更新数据库

         userInfoMapper.userWin(thatUser.getUserId());
         userInfoMapper.userLose(userInfo.getUserId());

         //防止内存泄漏，释放房间

        roomManager.remove(room.getRoomId(), room.getUser1().getUserId(),room.getUser2().getUserId());
    }
}
